/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#ifndef __TRANSFORM_GIZMO_H__
#define __TRANSFORM_GIZMO_H__

#include "PQEngine.h"

namespace PQBuilder
{
	class GizmoMaterialNames
	{
	public:
		static Ogre::String MATERIAL_TRANSLATE_X;
		static Ogre::String MATERIAL_TRANSLATE_Y;
		static Ogre::String MATERIAL_TRANSLATE_Z;

		static Ogre::String MATERIAL_ROTATE_X;
		static Ogre::String MATERIAL_ROTATE_Y;
		static Ogre::String MATERIAL_ROTATE_Z;

		static Ogre::String MATERIA_SCALE_X;
		static Ogre::String MATERIAL_SCALE_Y;
		static Ogre::String MATERIAL_SCALE_Z;

		static Ogre::String MATERIAL_NONE;
	};

	enum GizmoMode
	{
		GIZMO_MODE_SELECT,//select mode
		GIZMO_MODE_TRANSLATE,
		GIZMO_MODE_ROTATE,
		GIZMO_MODE_SCALE
	};
	
	/*Gizmo operation type that can perform.
	Determined by Gizmo composed part.
	*/
	enum GizmoOp
	{
		GIZMO_TRANSLATE_X,
		GIZMO_TRANSLATE_Y,
		GIZMO_TRANSLATE_Z,
		
		GIZMO_ROTATE_X,
		GIZMO_ROTATE_Y,
		GIZMO_ROTATE_Z,

		GIZMO_SCALE_X,
		GIZMO_SCALE_Y,
		GIZMO_SCALE_Z,
		
		GIZMO_OP_COUNT= GIZMO_SCALE_Z-GIZMO_TRANSLATE_X+1,
		GIZMO_OP_NONE
	};

	enum GizmoType
	{
		GIZMO_TYPE_LOCAL,

		GIZMO_TYPE_PARENT,
		GIZMO_TYPE_GLOBAL
	};

	/*TransformGizmo is a object that have only one for a scene object.
	This class can help user transform their object by input.
	Suite for user editable scene managment.
	*/
	class TransformGizmo :
		public PQEngine::Object
	{
	public:
		TransformGizmo(PQEngine::SceneObject* sceneObject);

		inline GizmoMode getMode(){return _mode;}

		void update(int x,int y);

		void setPosition(Ogre::Vector3 pos);
		Ogre::Vector3 getPosition();
		Ogre::Quaternion getOrientation();
		void setOrientation(Ogre::Quaternion orient);
		void setScale(Ogre::Vector3 scale);
		Ogre::Vector3 getScale();
		
		void setGizmoMode(GizmoMode mode);

		void translate(int x,int y);//accord camera
		void rotate(float delta);
		void scale(int x,int y);
		int getGizmoOp(){return _operation;}
		bool isGizmoSelected();

		//start transform by screen coord
		void startTransform(int x,int y);
		void stopTransform();
		inline bool isTransforming()
		{
			return _transforming;
		}
		void show(bool show);
	private:	
		//Update gizmo appearance by mouse picking,select axis
		bool updateGizmo(Ogre::Ray ray);//use selection ray to update gizmo
		//Update gizmo by camera settings,keep axis gizmo size not change from the screen
		void updateGizmo(Ogre::Vector3 cameraPosition);

		void restoreDefaultGizmo();

		void createGizmo();
		void createGizmoMaterial();
		

		void buildTranslateArrow(Ogre::ManualObject *mesh);
		void buildRotateArrow(Ogre::ManualObject *mesh);
		
		void setGizmoOp(GizmoOp op);

		inline GizmoOp getOp(){return _operation;}

		Ogre::Vector3 getWorldProjectionPosition(Ogre::Vector3 cameraDirection,Ogre::Ray ray);
		
	private:
		static bool _meshLoaded;
		static Ogre::MaterialPtr _materials[GIZMO_OP_COUNT];
		int _mouseX;
		int _mouseY;
		GizmoOp _operation;//the gizmo part that hightlighted

		PQEngine::SceneObject* _sceneObject;//owner

		GizmoMode _mode;

		Ogre::SceneManager* _sceneMgr;
		Ogre::MaterialManager* _materialMgr;
		Ogre::Camera* _camera;
		Ogre::SceneNode* _rootNode;

		Ogre::SceneNode* _nodes[GIZMO_OP_COUNT];
		Ogre::Entity* _entities[GIZMO_OP_COUNT];

		Ogre::ManualObject *_mesh;//mesh builder
		PQEngine::MeshData* _meshData;//used load selected mesh and test selection
		
		Ogre::Plane _translationPlane;//translation plane

		Ogre::Vector3 _lastProjectionDelta;
		Ogre::Vector3 _translateDelta;
		Ogre::Quaternion _lastOrientation;

		Ogre::Vector3 _scale;
		Ogre::Vector3 _position;
		Ogre::Quaternion _orient;
		//
		bool _transforming;
		bool _show;//is gizmo show.
	};
}
#endif
